"""
备份执行器模块

负责执行单个备份任务，根据配置文件创建相应的备份器并执行备份操作。
"""

import os
import logging
from typing import Dict, Any, Optional

from ..core import BackupConfig
from .mysql import MySQLBackup
from .postgresql import PostgreSQLBackup
from .mariadb import MariaDBBackup
from ..git import GitHandler


class BackupExecutor:
    """备份执行器
    
    负责执行单个备份任务，包括数据库备份和可选的Git上传。
    """
    
    def __init__(self, logger: logging.Logger):
        """初始化备份执行器
        
        参数:
            logger (logging.Logger): 日志记录器
        """
        self.logger = logger
    
    def execute_backup(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
        """执行备份任务
        
        参数:
            config_data (Dict[str, Any]): 备份任务配置数据
        
        返回:
            Dict[str, Any]: 执行结果
        """
        task_name = config_data.get('_config_name', 'unknown')
        
        try:
            self.logger.info(f"开始执行备份任务: {task_name}")
            
            # 创建备份配置对象
            backup_config = self._create_backup_config(config_data)
            if not backup_config:
                return {
                    'success': False,
                    'error': '无法创建备份配置',
                    'task_name': task_name
                }
            
            # 创建备份器
            backup = self._create_backup_instance(config_data, backup_config)
            if not backup:
                return {
                    'success': False,
                    'error': f"不支持的数据库类型: {config_data.get('type', 'unknown')}",
                    'task_name': task_name
                }
            
            # 生成输出文件名
            import datetime
            timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            output_dir = config_data.get('backup', {}).get('output_dir', './backups')
            database_name = config_data.get('database', {}).get('database', 'unknown')
            output_file = os.path.join(output_dir, f"{database_name}_backup_{timestamp}.sql")
            
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            # 执行数据库备份
            backup_result = backup.backup_database(output_file=output_file)
            if not backup_result.get('success', False):
                return {
                    'success': False,
                    'error': backup_result.get('error', '备份失败'),
                    'task_name': task_name
                }
            
            # 处理Git上传
            git_result = self._handle_git_upload(config_data, backup_result)
            
            # 返回成功结果
            result = {
                'success': True,
                'task_name': task_name,
                'message': '备份任务执行成功',
                'backup_file': backup_result.get('backup_file'),
                'backup_files': backup_result.get('backup_files', []),
                'file_size': backup_result.get('file_size'),
                'table_count': backup_result.get('table_count', 0),
                'git_uploaded': git_result.get('success', False)
            }
            
            if git_result.get('success', False):
                result.update({
                    'git_repo_url': git_result.get('repo_url'),
                    'git_commit_hash': git_result.get('commit_hash'),
                    'git_files_uploaded': git_result.get('files_uploaded', 0)
                })
            
            self.logger.info(f"备份任务 {task_name} 执行成功")
            return result
            
        except Exception as e:
            self.logger.error(f"备份任务 {task_name} 执行异常: {e}")
            return {
                'success': False,
                'error': str(e),
                'task_name': task_name
            }
    
    def _create_backup_config(self, config_data: Dict[str, Any]) -> Optional[BackupConfig]:
        """创建备份配置对象
        
        参数:
            config_data (Dict[str, Any]): 配置数据
        
        返回:
            Optional[BackupConfig]: 备份配置对象
        """
        try:
            # 获取数据库配置
            db_config = config_data.get('database', {})
            backup_config = config_data.get('backup', {})
            
            # 创建备份配置
            config = BackupConfig(
                host=db_config.get('host', 'localhost'),
                port=db_config.get('port', 3306),
                user=db_config.get('username', ''),
                password=db_config.get('password', ''),
                database=db_config.get('database', ''),
                output_dir=backup_config.get('output_dir', './backups'),
                filename=backup_config.get('filename', ''),
                tables=backup_config.get('tables', []),
                exclude_tables=backup_config.get('exclude_tables', []),
                compress=backup_config.get('compress', False),
                include_data=backup_config.get('include_data', True),
                include_schema=backup_config.get('include_schema', True)
            )
            
            # 设置SSL模式（PostgreSQL专用）
            if 'sslmode' in db_config:
                config.ssl_mode = db_config['sslmode']
            
            return config
            
        except Exception as e:
            self.logger.error(f"创建备份配置失败: {e}")
            return None
    
    def _create_backup_instance(self, config_data: Dict[str, Any], 
                               backup_config: BackupConfig):
        """创建备份器实例
        
        参数:
            config_data (Dict[str, Any]): 配置数据
            backup_config (BackupConfig): 备份配置
        
        返回:
            DatabaseBackup: 备份器实例
        """
        db_type = config_data.get('type', '').lower()
        db_config = config_data.get('database', {})
        backup_config_data = config_data.get('backup', {})
        
        # 从配置中提取参数
        host = db_config.get('host', 'localhost')
        port = db_config.get('port', 3306)
        # 修复字段名不匹配问题：使用username而不是user
        username = db_config.get('username', db_config.get('user', ''))
        password = db_config.get('password', '')
        database = db_config.get('database', '')
        backup_dir = backup_config_data.get('output_dir', './backups')
        
        if db_type == 'mysql':
            return MySQLBackup(
                host=host,
                port=port,
                username=username,
                password=password,
                database=database,
                backup_dir=backup_dir
            )
        elif db_type == 'postgresql':
            return PostgreSQLBackup(
                host=host,
                port=port,
                username=username,
                password=password,
                database=database,
                backup_dir=backup_dir
            )
        elif db_type == 'mariadb':
            return MariaDBBackup(
                host=host,
                port=port,
                username=username,
                password=password,
                database=database,
                backup_dir=backup_dir
            )
        else:
            self.logger.error(f"不支持的数据库类型: {db_type}")
            return None
    
    def _handle_git_upload(self, config_data: Dict[str, Any], 
                          backup_result: Dict[str, Any]) -> Dict[str, Any]:
        """处理Git上传
        
        参数:
            config_data (Dict[str, Any]): 配置数据
            backup_result (Dict[str, Any]): 备份结果
        
        返回:
            Dict[str, Any]: Git上传结果
        """
        try:
            backup_config = config_data.get('backup', {})
            
            # 检查是否启用自动上传
            auto_upload = backup_config.get('auto_upload', False)
            if not auto_upload:
                return {'success': False, 'message': 'Git上传未启用'}
            
            # 检查Git配置
            git_config = backup_config.get('git', {})
            local_path = git_config.get('local_path', '')
            
            if not local_path:
                return {'success': False, 'error': '未配置Git本地路径'}
            
            # 获取备份文件
            backup_files = backup_result.get('backup_files', [])
            if not backup_files:
                backup_file = backup_result.get('backup_file')
                if backup_file:
                    backup_files = [backup_file]
                else:
                    return {'success': False, 'error': '没有备份文件可上传'}
            
            # 创建Git处理器
            git_handler = GitHandler(self.logger)
            
            # 执行Git上传
            git_result = git_handler.upload_backup_files(
                backup_files=backup_files,
                repo_url='',  # 使用本地路径，不需要URL
                local_path=local_path,
                commit_message=git_config.get('commit_message', '数据库备份'),
                branch=git_config.get('branch', 'main'),
                username=git_config.get('username', ''),
                password=git_config.get('password', '')
            )
            
            if git_result.get('success', False):
                self.logger.info(f"Git上传成功: {git_result.get('files_uploaded', 0)} 个文件")
            else:
                self.logger.warning(f"Git上传失败: {git_result.get('error', '未知错误')}")
            
            return git_result
            
        except Exception as e:
            self.logger.error(f"Git上传处理异常: {e}")
            return {
                'success': False,
                'error': str(e)
            }
    
    def validate_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
        """验证配置数据
        
        参数:
            config_data (Dict[str, Any]): 配置数据
        
        返回:
            Dict[str, Any]: 验证结果
        """
        task_name = config_data.get('_config_name', 'unknown')
        
        try:
            # 检查必需字段
            required_fields = ['type', 'database', 'backup']
            missing_fields = []
            
            for field in required_fields:
                if field not in config_data:
                    missing_fields.append(field)
            
            if missing_fields:
                return {
                    'success': False,
                    'error': f"缺少必需字段: {', '.join(missing_fields)}",
                    'task_name': task_name
                }
            
            # 检查数据库类型
            db_type = config_data['type'].lower()
            if db_type not in ['mysql', 'postgresql', 'mariadb']:
                return {
                    'success': False,
                    'error': f"不支持的数据库类型: {db_type}",
                    'task_name': task_name
                }
            
            # 检查数据库配置
            db_config = config_data['database']
            required_db_fields = ['host', 'username', 'database']
            missing_db_fields = []
            
            for field in required_db_fields:
                if field not in db_config or not db_config[field]:
                    missing_db_fields.append(field)
            
            if missing_db_fields:
                return {
                    'success': False,
                    'error': f"数据库配置缺少必需字段: {', '.join(missing_db_fields)}",
                    'task_name': task_name
                }
            
            # 检查备份配置
            backup_config = config_data['backup']
            if 'output_dir' not in backup_config:
                return {
                    'success': False,
                    'error': "备份配置缺少输出目录",
                    'task_name': task_name
                }
            
            # 检查Git配置（如果启用自动上传）
            if backup_config.get('auto_upload', False):
                git_config = backup_config.get('git', {})
                if 'local_path' not in git_config or not git_config['local_path']:
                    return {
                        'success': False,
                        'error': "启用Git自动上传但未配置本地路径",
                        'task_name': task_name
                    }
            
            return {
                'success': True,
                'message': '配置验证通过',
                'task_name': task_name
            }
            
        except Exception as e:
            return {
                'success': False,
                'error': f"配置验证异常: {e}",
                'task_name': task_name
            }


def create_backup_executor(logger: logging.Logger) -> BackupExecutor:
    """创建备份执行器实例
    
    参数:
        logger (logging.Logger): 日志记录器
    
    返回:
        BackupExecutor: 备份执行器实例
    """
    return BackupExecutor(logger)